/**
 * ExpressionService.java
 * Created on  2015/4/1 12:33
 * 版本       修改时间         作者        修改内容
 * V1.0.1     2015/4/1     panzhuowen    初始版本
 */
package com.infitecs.eyas.expression.service;

import com.infitecs.eyas.expression.dao.ExpressionDao;
import com.infitecs.eyas.expression.model.Formula;
import com.infitecs.eyas.result.dao.MiddleResultDao;
import com.infitecs.eyas.result.model.MiddleResult;
import com.infitecs.eyas.session.SessionService;
import com.infitecs.eyas.session.model.Param;
import com.infitecs.eyas.util.*;
import com.infitecs.krill.mybatis.interceptor.PageInterceptor;
import com.infitecs.krill.mybatis.model.Page;
import fr.expression4j.core.Catalog;
import fr.expression4j.core.Expression;
import fr.expression4j.core.Parameters;
import fr.expression4j.factory.ExpressionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 类的描述信息
 *
 * @author panzhuowen
 * @version 1.0.1
 */
@Service
public class ExpressionService {

    private HashMap<String, Double> paramMap;

    @Autowired
    private ExpressionDao expressionDao;

    @Autowired
    private SessionService sessionService;

    @Autowired
    private MiddleResultDao middleResultDao;


    public List<Formula> getFormulaListPage(Page page,Formula formula) {
        PageInterceptor.startPage(page);
        return expressionDao.getFormulaListPage(formula);
    }

    public boolean delFormula(int id) {
        return expressionDao.delFormula(id);
    }

    public int addFormula(Formula formula) {
        formula.setParamer(getParameter(formula.getFormulaDescription()));
        formula.setFormulaDescription(formula.getFormulaDescription().trim());
        return expressionDao.addFormula(formula);
    }

    public Formula getFormula(int id) {
        return expressionDao.getFormula(id);
    }

    public int updateFormula(Formula formula) {
        formula.setParamer(getParameter(formula.getFormulaDescription()));
        formula.setFormulaDescription(ExpressionUtil.getInstance().trimExp(formula.getFormulaDescription()));
        return expressionDao.updateFormula(formula);
    }

    private String getParameter(String exp) {
        String FORMULA_PREFIX = "y(";
        String FORMULA_SUFFIX = ")=";
        return FORMULA_PREFIX + ExpressionUtil.getInstance().param(exp) + FORMULA_SUFFIX;
    }

    /**
     * 校验公式名是否已经存在
     *
     * @param formula 属性formulaName 存储公式名 memo存储的是过去的formulaName
     * @return 是否没重复？ true 没有 false 重复了，和自己的老名字重复了不叫重复，叫没改名字
     */
    public Boolean checkRepeatFormulaName(Formula formula) {
        //临时用memo存储老的公式名称
        return null == expressionDao.getFormulaByName(formula.getFormulaName()) || formula.getFormulaName().equals(formula.getMemo());
    }


    /**
     * 燃烧公式计算函数，直接传入caseId，和公式名称即可获取结果，但是必须经常维护这里的代码，保证每个用到的基本元素都必须加入代码当中
     * 注意：
     * 在使用这个方法的时候  参数 formulaName 必须是附带公式分类标识的
     * 处理步骤：
     * 步骤一：处理特殊计算
     * 步骤二：准备参数集合
     * 步骤三：计算公式结果
     * 步骤四：将结果装进map，并对中间值进行存储，然后随结果返回
     *
     * @param param 公式名称，再猜强调附带公式标识前缀
     * @return 计算结果
     */
    public Double dealSpecialCalculate(Param param) {
        //步骤一、
        if (null == param || null == param.getParamName() || "".equals(param.getParamName()))
            return null;
        //处理非一个参数的或者特殊的函数
        switch (sessionService.getE()) {
            case 'R':
                switch (param.getParamName()) {
                    case "RE38":
                        return calculateRE38();
                    //可将公式子式替换为 ET1192 插入临时子式 T1作为标识
                    case "RET1192":
                        return calculateRET1192();
                    case "RE241":
                        return calculateRE241();
                    case "RE242":
                        return calculateRE242();
                    case "RE255":
                        return calculateRE255();
                    case "RE260":
                        return calculateRE260();
                    case "RE295":
                        return calculateRE295();
                    case "RE300":
                        return calculateRE300();
                    case "RE324":
                        return calculateRE324();
                    case "RE329":
                        return calculateRE329();
                    case "RE331":
                        return calculateRE331();
                    default:
                        return null;
                }
            case 'A':
                switch (param.getParamName()) {
                    case "AE12":
                        return calculateAE12();
                    case "AE21":
                        return calculateAE21();
                    case "AE23":
                        return calculateAE23();
                    case "AE24":
                        return calculateAE24();
                    case "AE25":
                        return calculateAE25();
                    case "AE26":
                        return calculateAE26();
                    case "AE32":
                        return calculateAE32();
                    case "AE33":
                        return calculateAE33();
                    case "AE36":
                        return calculateAE36();
                    case "AE37":
                        return calculateAE37();
                    case "AE42":
                        return calculateAE42();
                    case "AE50":
                        return calculateAE50();
                    case "AE51":
                        return calculateAE51();
                    case "AE53":
                        return calculateAE53();
                    case "AE55":
                        return calculateAE55();
                    case "AE58":
                        return calculateAE58();
                    case "AE59":
                        return calculateAE59();
                    case "AE63":
                        return calculateAE63();
                    case "AE65":
                        return calculateAE65();
                    case "AE66":
                        return calculateAE66();
                    case "AE69":
                        return calculateAE69();
                    case "AE73":
                        return calculateAE73();
                    case "AE74":
                        return calculateAE74();
                    case "AE80":
                        return calculateAE80();
                    case "AE81":
                        return calculateAE81();
                    case "AE84":
                        return calculateAE84();
                    case "AE94":
                        return calculateAE94();
                    case "AE95":
                        return calculateAE95();
                    case "AE103":
                        return calculateAE103();
                    case "AE107":
                        return calculateAE107();
                    case "AE111":
                        return calculateAE111();
                    case "AE120":
                        return calculateAE120();
                    default:
                        return null;
                }
            case 'K':
                switch (param.getParamName()) {
                    case "KE8":
                        return calculateKE8();
                    case "KE15":
                        return calculateKE15();
                    case "KE16":
                        return calculateKE16();
                    case "KE17":
                        return calculateKE17();
                    case "KE23":
                        return calculateKE23();
                    case "KE34":
                        return calculateKE34();
                    case "KE35":
                        return calculateKE35();
                    case "KE36":
                        return calculateKE36();
                    case "KE37":
                        return calculateKE37();
                    case "KE38":
                        return calculateKE38();
                    case "KE44":
                        return calculateKE44();
                    case "KE54":
                        return calculateKE54();
                    case "KE55":
                        return calculateKE55();
                    case "KE63":
                        return calculateKE63();
                    default:
                        return null;
                }
            case 'Y':
                switch (param.getParamName()) {
                    case "YE11":
                        return calculateYE11();
                    default:
                        return null;
                }
            case 'C':
                switch (param.getParamName()) {
                    case "CE15":
                        return calculateCE15();
                    default:
                        return null;
                }
            case 'S':
                switch (param.getParamName()) {
                    case "SE10":
                        return calculateSE10();
                    default:
                        return null;
                }
            default:
                return null;
        }
    }

    private Double calculateSE10() {
        Double E6 = paramMap.get("SE6");
        if (E6 == 1) {
            return calculate(new Param("SE10_1"));
        } else {
            return calculate(new Param("SE10_2"));
        }
    }

    private Double calculateKE63() {
        Double er = null;
        Double E32 = paramMap.get("KE32");
        Double E17 = paramMap.get("KE17");
        Double aa;
        if (0.05 <= E32 / E17 && E32 / E17 <= 0.5) {
            aa = calculate(new Param("KE38_1"));
        } else {
            aa = -1.0;
        }
        Double bb;
        Double E4 = paramMap.get("KE4");
        Double E5 = paramMap.get("KE5");
        Double E6 = paramMap.get("KE6");
        if (E4 == 1 || E5 == E6) {
            bb = 1.0;
        } else {
            bb = calculate(new Param("KE38_2"));
        }
        Double cc;
        Double E18 = paramMap.get("KE18");
        Double E16 = paramMap.get("KE16");
        Double E21 = paramMap.get("KE21");
        Double E22 = paramMap.get("KE22");
        Double E23 = paramMap.get("KE23");
        if (0.5 <= E32 / E17 && E32 / E17 <= 0.55 && 0 < (E18 / E16) && (E18 / E16) <= 0.001 && E21 > 40000) {
            cc = calculate(new Param("KE38_3"));
        } else if (E32 / E17 > 0.55 && 40000 < E21 && E21 < 200000 && 0 < E18 / E16 && E18 / E16 <= 0.001) {
            cc = E23 / E22;
        } else if (E32 / E17 > 0.55 && E21 > 200000 && 0 < E18 / E16 && E18 / E16 <= 0.001) {
            cc = calculate(new Param("KE38_4"));
        } else if (E32 / E17 > 0.55 && E21 > 40000 && E18 / E16 > 0.001) {
            cc = 2.0;
        } else {
            cc = 1.0;
        }
        Double dd;
        if (E21 > 200000) {
            dd = 1.0;
        } else {
            dd = 64 * E22;
        }
        Double E61 = paramMap.get("KE61");
        if (aa != -1.0) {
            er = Math.exp(-(2.3 * Math.log(Math.pow(aa * bb * cc * dd, -1))) / (E61 / E5));
        }
        return er;
    }

    private Double calculateCE15() {
        Double E6 = paramMap.get("CE6");
        if (E6 == 1) {
            return calculate(new Param("CE15_1"));
        } else {
            return calculate(new Param("CE15_2"));
        }
    }

    private Double calculateYE11() {
        Double temp1 = calculate(new Param("YE11_1"));
        Double temp2 = calculate(new Param("YE11_2"));
        return temp1 > temp2 ? temp1 : temp2;
    }

    private Double calculateKE55() {
        Double E21 = paramMap.get("KE21");
        Double E18 = paramMap.get("KE18");
        Double E16 = paramMap.get("KE16");
        if (E21 * 0.001 >= 3 && E21 * 0.001 <= 40) {
            return 1.0;
        } else if (E21 * 0.001 > 40 && 0 < E18 / E16 && E18 / E16 <= 0.001) {
            return calculate(new Param("KE55_1"));
        } else {
            return 1.5;
        }
    }

    private Double calculateKE54() {
        Double E4 = paramMap.get("KE4");
        if (E4 == 1) {
            return 0.97;
        } else {
            return calculate(new Param("KE54_1"));
        }
    }

    private Double calculateKE44() {
        Double E32 = paramMap.get("KE32");
        Double E17 = paramMap.get("KE17");
        if (0.05 <= E32 / E17 && E32 / E17 <= 0.5) {
            return calculate(new Param("KE44_1"));
        } else {
            return -1.0;
        }
    }

    private Double calculateKE38() {
        Double E21 = paramMap.get("KE21");
        Double E22 = paramMap.get("KE22");
        if (E21 > 200000) {
            return 1.0;
        } else {
            return 64 * E22;
        }
    }

    private Double calculateKE37() {
        Double E16 = paramMap.get("KE16");
        Double E17 = paramMap.get("KE17");
        Double E18 = paramMap.get("KE18");
        Double E21 = paramMap.get("KE21");
        Double E32 = paramMap.get("KE32");
        if (0.5 <= E32 / E17 && E32 / E17 <= 0.55 && 0 < (E18 / E16) && (E18 / E16) <= 0.001 && E21 > 40000) {
            return calculate(new Param("KE37_1"));
        } else if (E32 / E17 > 0.55 && 40000 < E21 && E21 < 200000 && 0 < E18 / E16 && E18 / E16 <= 0.001) {
            return calculate(new Param("KE37_2"));
        } else if (E32 / E17 > 0.55 && E21 > 200000 && 0 < E18 / E16 && E18 / E16 <= 0.001) {
            return calculate(new Param("KE37_2"));
        } else if (E32 / E17 > 0.55 && E21 > 40000 && E18 / E16 > 0.001) {
            return 2.0;
        } else {
            return 1.0;
        }
    }

    private Double calculateKE36() {
        Double E4 = paramMap.get("KE4");
        Double E5 = paramMap.get("KE5");
        Double E6 = paramMap.get("KE6");
        if (E4 == 1 || E5 == E6) {
            return 1.0;
        } else {
            return calculate(new Param("KE36_1"));
        }
    }

    private Double calculateKE35() {
        Double E32 = paramMap.get("KE32");
        Double E17 = paramMap.get("KE17");
        Double temp = E32 / E17;
        if (temp > 0.5 && temp <= 1) {
            return calculate(new Param("KE35_1"));
        } else if (temp > 1) {
            return calculate(new Param("KE35_2"));
        } else {
            return -1.0;
        }
    }

    private Double calculateKE34() {
        Double E31 = paramMap.get("E34");
        if (E31 <= 70) {
            return calculate(new Param("KE34_1"));
        } else if (E31 >= 100) {
            return calculate(new Param("KE34_2"));
        } else {
            return 1.0;
        }
    }

    private Double calculateKE23() {
        Double E21 = paramMap.get("KE21");
        Double E18 = paramMap.get("KE18");
        Double E16 = paramMap.get("KE16");
        Double temp = 560 / (E18 / E16);
        if (E21 < temp) {
            return calculate(new Param("KE23_1"));
        } else {
            return calculate(new Param("KE23_2"));
        }
    }

    private Double calculateKE17() {
        Double E4 = paramMap.get("KE4");
        if (E4 == 1) {
            return calculate(new Param("KE17_1"));
        } else {
            return calculate(new Param("KE17_2"));
        }
    }

    private Double calculateKE16() {
        Double E4 = paramMap.get("KE4");
        if (E4 == 1) {
            return calculate(new Param("KE16_1"));
        } else {
            return calculate(new Param("KE16_2"));
        }
    }

    private Double calculateKE15() {
        Double E4 = paramMap.get("KE4");
        if (E4 == 1) {
            return calculate(new Param("KE15_1"));
        } else {
            return calculate(new Param("KE15_2"));
        }
    }

    private Double calculateKE8() {
        Double E4 = paramMap.get("KE4");
        Double E7 = paramMap.get("KE7");
        if (E4 == 1) {
            return E7;
        } else {
            return calculate(new Param("KE8_1"));
        }

    }

    /**
     * 处理特殊公式AE12  = IF(AE12_1,AE12_2,AE12_3)
     * 计算 AE12
     * AE12_1=AND((ME6*100/(100-ME3))>29,ME13>15510,ME13<17000)
     * AE12_2=5+0.35*E2*ME10
     * AE12_3=IF(AND(ME10>38,ME3>20),35,0.5*E2*ME10)
     *
     * @return 结算结果
     */
    private Double calculateAE12() {
        Double E2 = paramMap.get("AE2");
        Double ME6 = paramMap.get("ME6");
        Double ME3 = paramMap.get("ME3");
        Double ME13 = paramMap.get("ME13");
        Double ME10 = paramMap.get("ME10");
        if (null == E2 || null == ME6 || null == ME3 || null == ME13 || null == ME10)
            return null;
        boolean AE12_1 = (ME6 * 100 / (100 - ME3)) > 29 && ME13 > 15510 && ME13 < 17000;
        Double AE12_2 = 5 + 0.35 * E2 * ME10;
        Double AE12_3 = (ME10 > 38 && ME3 > 20) ? 35 : 0.5 * E2 * ME10;
        return AE12_1 ? AE12_2 : AE12_3;
    }

    private Double calculateAE21() {
        Double ME3 = paramMap.get("ME3");
        if (ME3 == null)
            return null;
        return ME3 <= 10 ? 1 : (1 + (10 - ME3) * 0.0114);
    }

    private Double calculateAE23() {
        Double ME3 = paramMap.get("ME3");
        Double E11 = paramMap.get("AE11");
        if (E11 == null || ME3 == null)
            return null;
        if (E11 <= 32.6) {
            if (ME3 <= 12)
                return 1.0;
            else
                return 1 + (12 - ME3) * 0.0125;
        } else {
            if (ME3 <= 8)
                return 1.0;
            else
                return 1 + (8 - ME3) * 0.0125;
        }
    }

    public Double calculateAE24() {
        Double ME3 = paramMap.get("ME3");
        if (ME3 == null)
            return null;
        if (ME3 < 10)
            return 1.0;
        else if (ME3 >= 10 && ME3 <= 14)
            return 1 + 0.0125 * (10 - ME3);
        else
            return null;
    }

    public Double calculateAE25() {
        Double ME6 = paramMap.get("ME6");
        if (ME6 == null)
            return null;
        if (ME6 > 20)
            return 1 + 0.005 * (20 - ME6);
        else
            return 1.0;
    }

    public Double calculateAE26() {
        Double ME6 = paramMap.get("ME6");
        if (ME6 == null)
            return null;
        if (ME6 <= 20)
            return 1.2;
        else if (ME6 >= 40)
            return 1.05;
        else
            return 1.05 + (40 - ME6) * 0.0075;
    }

    public Double calculateAE32() {
        Double E32;
        Double E12 = paramMap.get("AE12");
        if (E12 == null)
            return null;
        if (E12 > 25) {
            E32 =  1.0;
        } else if (E12 >= 18 && E12 <= 25) {
            E32 = 1 + (25 - E12) * 0.01;
        } else {
            E32 = 1.07;
        }
        paramMap.put("AE32",E32);
        return E32;
    }

    public Double calculateAE33() {
        Double E7 = paramMap.get("AE7");
        if (E7.equals(1.0) || E7.equals(2.0) || E7.equals(3.0) || E7.equals(4.0) || E7.equals(5.0) || E7.equals(6.0)) {
            return calculate(new Param("AE33_1"));
        } else if (E7.equals(7.0)) {
            return calculate(new Param("AE33_2"));
        } else if (E7.equals(8.0)) {
            return calculate(new Param("AE33_3"));
        } else if (E7.equals(9.0)) {
            return calculate(new Param("AE33_4"));
        } else {
            return null;
        }
    }

    public Double calculateAE36() {
        Double E36;
        Double E7 = paramMap.get("AE7");
        if (E7.equals(1.0) || E7.equals(2.0) || E7.equals(3.0) || E7.equals(4.0) || E7.equals(5.0) || E7.equals(6.0) || E7.equals(7.0)) {
            E36 = calculate(new Param("AE36_1"));
        } else if (E7.equals(8.0)) {
            E36 = calculate(new Param("AE36_2"));
        } else if (E7.equals(9.0)) {
            E36 = calculate(new Param("AE36_3"));
        } else {
            return null;
        }
        paramMap.put("AE36",E36);
        return E36;
    }

    private Double calculateAE37() {
        Double E35 = paramMap.get("AE35");
        Double E10 = paramMap.get("AE10");
        if (E35 / E10 > 1.1) {
            paramMap.put("AE37",E35 / E10);
            return E35 / E10;
        }
        else
            return null;
    }

    private Double calculateAE42() {
        Double E42;
        Double E7 = paramMap.get("AE7");
        if (E7.equals(1.0) || E7.equals(2.0) || E7.equals(3.0) || E7.equals(4.0) || E7.equals(5.0) || E7.equals(6.0) || E7.equals(7.0)) {
            E42 =  calculate(new Param("AE42_1"));
        } else if (E7.equals(8.0) || E7.equals(9.0)) {
            E42 =  calculate(new Param("AE42_2"));
        } else {
            return null;
        }
        paramMap.put("AE42",E42);
        return E42;
    }

    private Double calculateAE50() {
        Double E38 = paramMap.get("AE38");
        if (E38 == null)
            return null;
        if (E38 > 25)
            return 66.666667 + 0.3333333 * E38;
        else
            return 75.0;
    }

    private Double calculateAE51() {
        Double E38 = paramMap.get("AE38");
        if (E38 == null)
            return null;
        if (E38 > 25)
            return 60 + 0.4 * E38;
        else
            return 70.0;
    }

    private Double calculateAE53() {
        Double E53;
        Double E7 = paramMap.get("AE7");
        Double E52 = paramMap.get("AE52");
        if (E7.equals(1.0) || E7.equals(2.0) || E7.equals(3.0) || E7.equals(4.0) || E7.equals(5.0) || E7.equals(6.0) || E7.equals(7.0)) {
            E53 = E52 * 0.75;
        } else {
            E53 =  E52 * 0.7;
        }
        paramMap.put("AE53",E53);
        return E53;
    }

    private Double calculateAE55() {
        Double E55;
        Double E7 = paramMap.get("AE7");
        if (E7.equals(1.0) || E7.equals(2.0) || E7.equals(3.0) || E7.equals(4.0) || E7.equals(5.0) || E7.equals(6.0) || E7.equals(7.0)) {
            E55 =  calculate(new Param("AE55_1"));
        } else {
            E55 = calculate(new Param("AE55_2"));
        }
        paramMap.put("AE55",E55);
        return E55;
    }

    private Double calculateAE58() {
        Double E58;
        Double E7 = paramMap.get("AE7");
        if (E7.equals(1.0) || E7.equals(2.0) || E7.equals(3.0) || E7.equals(4.0) || E7.equals(5.0) || E7.equals(6.0) || E7.equals(7.0)) {
            E58 = calculate(new Param("AE58_1"));
        } else {
            E58 = calculate(new Param("AE58_2"));
        }
        paramMap.put("AE58",E58);
        return E58;
    }

    private Double calculateAE59() {
        Double E52 = paramMap.get("AE52");
        Double E58 = paramMap.get("AE58");
        Double E56 = paramMap.get("AE56");
        Double E53 = paramMap.get("AE53");
        if (E52 == null || E58 == null || E56 == null || E53 == null)
            return null;
        if (E52 >= E58 && E56 >= E53)
            return 1.0;            /*合格*/
        else
            return null;            /*请重新设定锅炉一次风率或选择其他型号*/
    }

    private Double calculateAE63() {
        Double E63;
        Double ME3 = paramMap.get("ME3");
        Double ME13 = paramMap.get("ME13");
        if (ME3 == null || ME13 == null)
            return null;
        if (ME3 < (ME13 * 0.001) / 0.65)
            E63 = 0.0;
        else
            E63 = 0.2;
        paramMap.put("AE63",E63);
        return E63;
    }

    private Double calculateAE65() {
        Double E65;
        Double ME3 = paramMap.get("ME3");
        Double ME13 = paramMap.get("ME13");
        Double E64 = paramMap.get("AE64");
        if (ME3 == null || ME13 == null || E64 == null)
            return null;
        if (ME3 < (ME13 * 0.001) / 0.65)
            E65 = 0.0;
        else
            E65 = 0.2 * E64;
        paramMap.put("AE65",E65);
        return E65;
    }

    private Double calculateAE66() {
        Double E66;
        Double E7 = paramMap.get("AE7");
        if (E7 == null)
            return null;
        if (E7.equals(1.0) || E7.equals(2.0) || E7.equals(3.0) || E7.equals(4.0) || E7.equals(5.0) || E7.equals(6.0) || E7.equals(7.0)) {
            E66 = 0.6 * 20;
        } else {
            E66 = 0.6 * 22;
        }
        paramMap.put("AE66",E66);
        return E66;
    }

    private Double calculateAE69() {
        Double E69;
        Double E61 = paramMap.get("AE61");
        Double E56 = paramMap.get("AE56");
        if (E61 == 0)
            E69 = E56 * 0.05;
        else
            E69 = 0.0;
        paramMap.put("AE69",E69);
        return E69;
    }

    private Double calculateAE73() {
        Double E73;
        Double ME10 = paramMap.get("ME10");
        if (ME10 < 40)
            E73 = calculate(new Param("AE73_1"));
        else
            E73 = 70.0;
        paramMap.put("AE73",E73);
        paramMap.put("AE74",E73);
        return E73;
    }

    private Double calculateAE74() {
        return calculateAE73();
    }

    private Double calculateAE80() {
        Double ME10 = paramMap.get("ME10");
        Double ME6 = paramMap.get("ME6");
        Double ME3 = paramMap.get("ME3");
        Double E74 = paramMap.get("AE74");
        Double E63 = paramMap.get("AE63");
        if (ME10 == null || ME6 == null || ME3 == null || E74 == null || E63 == null)
            return null;
        if (ME10 > 10) {
            Double E80 =calculate(new Param("AE80_1"));
            paramMap.put("AE80",E80);
            return E80;
        }

        else {
            Double E80 = calculate(new Param("AE80_2"));
            paramMap.put("AE80",E80);
            return E80;
        }

    }

    private Double calculateAE81() {
        Double E80;
        Double ZE12 = paramMap.get("ZE12");
        Double ME3 = paramMap.get("ME3");
        Double ME4 = paramMap.get("ME4");
        if (ZE12 == null || ME3 == null || ME4 == null)
            return null;
        if (ZE12 > 0)
            E80 = 0.0;
        else
            E80 = calculate(new Param("AE81_1"));
        paramMap.put("AE81",E80);
        return E80;
    }


    private Double calculateAE84() {
        Double E84;
        Double E61 = paramMap.get("AE61");
        Double E77 = paramMap.get("AE77");
        Double E79 = paramMap.get("AE79");
        Double E82 = paramMap.get("AE82");
        if (E61 == null || E77 == null || E79 == null || E82 == null)
            return null;
        if (E61 == 0)
            E84 = calculate(new Param("AE84_1"));
        else
            E84 = calculate(new Param("AE84_2"));
        paramMap.put("AE84",E84);
        return E84;
    }

    private Double calculateAE94() {
        Double E94;
        Double E93 = paramMap.get("AE93");
        Double E91 = paramMap.get("AE91");
        if (E93 == null || E91 == null)
            return null;
        if (calculate(new Param("AE94_1")) < 0.003)
            E94 = calculate(new Param("AE94_1"));   /*判断条件 与输出 是同一个  abs((E93-E91)/E93)*/
        else
            return null;                               /*不合格*/
        paramMap.put("AE94",E94);
        return E94;
    }


    private Double calculateAE95() {
        Double E95;
        Double E93 = paramMap.get("AE93");
        Double GE40 = paramMap.get("GE40");
        if (E93 == null || GE40 == null)
            return null;
        if (calculate(new Param("AE95_1")) < 0.003)
            E95 = calculate(new Param("AE95_1"));   /*判断条件 与输出 是同一个 abs((E93-GE40)/E93)*/
        else
            E95 = null;                            /*请调整锅炉计算中磨煤机入口温度*/
        paramMap.put("AE95",E95);
        return E95;
    }

    private Double calculateAE103() {
        Double E103;
        Double E102 = paramMap.get("AE102");
        if (E102 == null)
            return null;
        if (0 < E102 && E102 <= 9)
            E103 = calculate(new Param("AE103_1"));
        else if (9 < E102 && E102 <= 512)
            E103 = calculate(new Param("AE103_2"));
        else
            E103 = calculate(new Param("AE103_3"));
        paramMap.put("AE103",E103);
        return E103;
    }

    private Double calculateAE107() {
        Double E107;
        Double E7 = paramMap.get("AE7");
        Double E69 = paramMap.get("AE69");
        if (E7 == null || E69 == null)
            return null;
        if (E7.equals(1.0) || E7.equals(2.0) || E7.equals(3.0) || E7.equals(4.0) || E7.equals(5.0) || E7.equals(6.0))
            E107 = null;                    /*数据库*/
        else
            E107 = E69 * 3.6;
        paramMap.put("AE107",E107);
        return E107;
    }

    private Double calculateAE111() {
        Double E111;
        Double E106 = paramMap.get("AE106");
        Double E99 = paramMap.get("AE99");
        Double E10 = paramMap.get("AE10");
        if (E106 == null || E99 == null || E10 == null)
            return null;
        if (E106 * 3.6 / E99 > E10)
            E111 =  E106 * 3.6 / E99;
        else
            E111 = null;            /*不合格*/
        paramMap.put("AE111",E111);
        return E111;
    }

    private Double calculateAE120() {
        Double E120;
        Double E100 = paramMap.get("AE100");
        Double E115 = paramMap.get("AE115");
        Double E118 = paramMap.get("AE118");
        Double E119 = paramMap.get("AE119");
        paramMap.put("EPI314", Math.PI);
        if (E100 == null || E115 == null || E118 == null || E119 == null)
            return null;
        if (22 <= calculate(new Param("AE120_1")) && calculate(new Param("AE120_2")) <= 28)
            E120 = calculate(new Param("AE120_3"));
        else
            E120 = null;                 /*不合格*/
        paramMap.put("AE120",E120);
        return E120;
    }


    public Double calculate(Param param) {
        paramMap = sessionService.getParamMap();
        Double result = dealSpecialCalculate(param);
        if (null != result)
            return result;
        int caseId = sessionService.getCaseId();
        Formula formula = expressionDao.getFormulaByName(param.getParamName());
        if (null == formula) {
            //当是必须是页面输入值，开头位E，这种公式是找不到的，所以计算失败！最好有办法直接结束此次结算
            return null;
        }
        String[] elementList = ExpressionUtil.getInstance().param(formula.getFormulaDescription()).split(",");
        //步骤二、
        Set<Parameter> parameters = getFormulaParameter(elementList);
        //求参失败！直接返回null
        if (null == parameters)
            return null;
        //步骤三、
        result = getFormulaValue(formula, parameters);
        //步骤四、
        if (null != result) {
            //如果该公式是中间值或输出得话 添加到中间值表里面
            middleResultDao.upMiddleResult(new MiddleResult(caseId, formula.getFormulaName(), result));
            //结算结果添加到map里面,这时候有分情况了，属于当前函数类型的去掉前缀
            paramMap.put(param.getParamName(), result);
        }
        return result;
    }

    public double getCalculateData(Formula formula, Map map) {
        String formulaDescription =formula.getFormulaDescription().replace("E-","*10^-").replace("E+","*10^");
        formula.setFormulaDescription(formulaDescription);
        String[] elementList = ExpressionUtil.getInstance().param(formula.getFormulaDescription()).split(",");
        Set<Parameter> parameters = getFormulaParameter(elementList, map);
        return getFormulaValue(formula, parameters);
    }

    public double getCalculateData6(Formula formula, Map map) {
        String formulaDescription =formula.getFormulaDescription().replace("E-","*10^-").replace("E+","*10^");
        formula.setFormulaDescription(formulaDescription);
        String[] elementList = ExpressionUtil.getInstance().param(formula.getFormulaDescription()).split(",");
        Set<Parameter> parameters = getFormulaParameter(elementList, map);
        return getFormulaValue6(formula, parameters);
    }


    /**
     * 为公式准备参数，将参数放入的一个set里面
     *
     * @param elementList 需要准备的参数列表
     * @return 将参数的值 装到一个set里面返回
     */
    private Set<Parameter> getFormulaParameter(String[] elementList) {
        Set<Parameter> parameters = new HashSet<>();
        for (String ex : elementList) {
            //避免split()函数结果包含空串，如果想屏蔽无关变量也可以写在里面
            if ("".equals(ex))
                continue;
            //情况一：求参数的时候默认先从session当中拿，但是调用函数的时候都用大名（意思是包含前缀）
            String paramName = ('E' == ex.charAt(0) && !ex.contains("EPI314") ? sessionService.getE() : "") + ex;
            Double value = paramMap.get(paramName);
            //情况二：发现找不到，就调用计算逻辑，向下运算
            if (null == value) {
                //当开头是E的加上公式前缀，进行公式求解
                value = calculate(new Param(paramName));
            }
            //情况三：如果结果还是null的话，就快点出去
            if (null == value) {
                return null;
            } else {
                parameters.add(new Parameter(ex, value));
            }
        }
        return parameters;
    }


    private Set<Parameter> getFormulaParameter(String[] elementList,Map<String,Double> map) {
        Set<Parameter> parameters = new HashSet<>();
        for (String ex : elementList) {
            //避免split()函数结果包含空串，如果想屏蔽无关变量也可以写在里面
            if ("".equals(ex))
                continue;
            //情况一：求参数的时候默认先从session当中拿，但是调用函数的时候都用大名（意思是包含前缀）
            String paramName = ('E' == ex.charAt(0) && !ex.contains("EPI314") ? sessionService.getE() : "") + ex;
            //情况二：发现找不到，就调用计算逻辑，向下运算
                parameters.add(new Parameter(ex, map.get(ex)));
        }
        return parameters;
    }

    /**
     * 将准备好的参数，以及公式的表示求得计算结果
     *
     * @param formula 公式VO
     * @param set     参数集合
     * @return 计算结果
     */
    private Double getFormulaValue(Formula formula, Set<Parameter> set) {
        Double er = null;
        //添加自定义公式
        Catalog catalog = ExpressionFactory.createCatalog("catalog");
        catalog.addExpression(new Functions.ATANS());
        catalog.addExpression(new Functions.DEGREE());
        catalog.addExpression(new Functions.LOG());
        catalog.addExpression(new Functions.LOGFUN());
        catalog.addExpression(new Functions.LOG10FUN());
        catalog.addExpression(new Functions.EXPFUN());
        catalog.addExpression(new Functions.SQRTFUN());
        catalog.addExpression(new Functions.SINFUN());
        catalog.addExpression(new Functions.TANFUN());
        catalog.addExpression(new Functions.TANHFUN());
        try {

            Expression expression = ExpressionFactory.createExpression(formula.getParamer() + formula.getFormulaDescription(), catalog);
            Parameters parameters = ParametersUtil.getParameters(set);
            er = DoubleUtil.getInstance().get4Double(expression.evaluate(parameters).getRealValue());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return er;
    }

    private Double getFormulaValue6(Formula formula, Set<Parameter> set) {
        Double er = null;
        //添加自定义公式
        Catalog catalog = ExpressionFactory.createCatalog("catalog");
        catalog.addExpression(new Functions.ATANS());
        catalog.addExpression(new Functions.DEGREE());
        catalog.addExpression(new Functions.LOG());
        catalog.addExpression(new Functions.LOGFUN());
        catalog.addExpression(new Functions.LOG10FUN());
        catalog.addExpression(new Functions.EXPFUN());
        catalog.addExpression(new Functions.SQRTFUN());
        catalog.addExpression(new Functions.SINFUN());
        catalog.addExpression(new Functions.TANFUN());
        catalog.addExpression(new Functions.TANHFUN());
        try {

            Expression expression = ExpressionFactory.createExpression(formula.getParamer() + formula.getFormulaDescription(), catalog);
            Parameters parameters = ParametersUtil.getParameters(set);
            er = DoubleUtil.getInstance().get6Double(expression.evaluate(parameters).getRealValue());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return er;
    }

    /**
     * 处理特殊公式30 计算RE38
     *
     * @return 结算结果
     */
    private Double calculateRE38() {
        Double RE38_1 = calculate(new Param("RE38_1"));
        if (null == RE38_1)
            return null;
        Double RE38_2 = calculate(new Param("RE38_2"));
        if (null == RE38_2)
            return null;
        return RE38_1 > RE38_2 ? RE38_1 : RE38_2;
    }

    /**
     * 处理特殊公式165  =  (IF(ME30<=1,0.15,IF(OR(ME30>1,ME30<=2),0.11,IF(ME30>2,0.137))))*(100*(E38-1))^0.86
     * 计算 RE192
     *
     * @return 计算结果
     */
    private Double calculateRET1192() {
        Double ME30 = paramMap.get("ME30");
        if (null == ME30)
            return null;
        //计算子式   RET1192  =  IF(ME30<=1,0.15,IF(OR(ME30>1,ME30<=2),0.11,IF(ME30>2,0.137)))
        return (ME30 <= 1) ? 0.15 : (ME30 > 1 || ME30 <= 2) ? 0.11 : 0.137;
    }

    /**
     * 处理特殊公式274  =  AND(0<=GE129,GE129<0.05)?800:RE241_4
     * RE241_1=AND(30<=GE129,GE129<45)?415:300
     * RE241_2=AND(20<=GE129,GE129<30)?440:RE241_1
     * RE241_3=AND(1<=GE129,GE129<20)?475:RE241_2
     * RE241_4=AND(0.05<=GE129,GE129<1)?556:RE241_3
     * 计算 RE241
     *
     * @return 结算结果
     */
    private Double calculateRE241() {
        Double GE129 = calculate(new Param("GE129"));
        if (null == GE129)
            return null;
        Double RE241_1 = 30 <= GE129 && GE129 < 45 ? 415.0 : 300.0;
        Double RE241_2 = 20 <= GE129 && GE129 < 30 ? 440 : RE241_1;
        Double RE241_3 = 1 <= GE129 && GE129 < 20 ? 475 : RE241_2;
        Double RE241_4 = 0.05 <= GE129 && GE129 < 1 ? 556 : RE241_3;
        return 0 <= GE129 && GE129 < 0.05 ? 800 : RE241_4;
    }

    /**
     * 处理特殊公式275  =  IF(ME36<15,RE242_1,RE242_2)
     * 计算 RE242
     *
     * @return 结算结果
     */
    private Double calculateRE242() {
        Double ME36 = paramMap.get("ME36");
        if (null == ME36)
            return null;
        Double RE242_1 = calculate(new Param("RE242_1"));
        Double RE242_2 = calculate(new Param("RE242_2"));
        return ME36 < 15 ? RE242_1 : RE242_2;
    }

    /**
     * 处理特殊公式241  = 	IF(ME35<(ME36+ME38+ME41+ME40),1,-1)  1:表示酸性，-1:表示碱性
     * 计算 RE255
     *
     * @return 结算结果
     */
    private Double calculateRE255() {
        Double ME35 = paramMap.get("ME35");
        if (null == ME35)
            return null;
        Double RE255_1 = calculate(new Param("RE255_1"));
        if (null == RE255_1)
            return null;
        return ME35 < RE255_1 ? 1.0 : -1.0;
    }

    /**
     * 处理特殊公式217  =   (RE260_1 + RE260_2) * RE260_3
     * 计算 RE260
     *
     * @return 结算结果
     */
    private Double calculateRE260() {
        Double RE260_2;
        Double ET1260 = calculate(new Param("RET1260"));
        if (null == ET1260)
            return null;
        if (1 - ET1260 > 0) {
            RE260_2 = calculate(new Param("RE260_2"));
        } else {
            RE260_2 = 0 - calculate(new Param("RE260_4"));
        }
        if (null == RE260_2)
            return null;
        Double RE260_1 = calculate(new Param("RE260_1"));
        if (null == RE260_1)
            return null;
        Double RE260_3 = calculate(new Param("RE260_3"));
        if (null == RE260_3)
            return null;
        return (RE260_1 + RE260_2) * RE260_3;
    }

    /**
     * 处理特殊公式250  =  RE295_4
     * 计算 RE295
     *
     * @return 结算结果
     */
    private Double calculateRE295() {
        Double RE295_1 = calculate(new Param("RE295_1"));
        if (null == RE295_1)
            return null;
        Double RE295_2 = calculate(new Param("RE295_2"));
        if (null == RE295_2)
            return null;
        Double RE295_3 = calculate(new Param("RE295_3"));
        if (null == RE295_3)
            return null;
        paramMap.put("RET1295", RE295_1 < 1.9 ? RE295_2 : RE295_3);
        return calculate(new Param("RE295_4"));
    }

    /**
     * 处理特殊公式254  =   RE300_4
     * 计算 RE300
     *
     * @return 结算结果
     */
    private Double calculateRE300() {
        Double RE300_1 = calculate(new Param("RE300_1"));
        if (null == RE300_1)
            return null;
        Double RE300_2 = calculate(new Param("RE300_2"));
        if (null == RE300_2)
            return null;
        Double RE300_3 = calculate(new Param("RE300_3"));
        if (null == RE300_3)
            return null;
        paramMap.put("RET1300", RE300_1 < 1.9 ? RE300_2 : RE300_3);
        return calculate(new Param("RE300_4"));
    }

    /**
     * 处理特殊公式268  = IF(E320=0,E325,IF(E320=1,(4*E316/22/PI())^0.5,IF(E320=2,(4*E316/20/PI())^0.5,IF(E320=3,(4*E316/18/PI())^0.5,-1))))
     * 计算 RE324
     * 如果结果为 -1 表示用户没有选择内衬类型，提示用户选择
     *
     * @return 结算结果
     */
    private Double calculateRE324() {
        Double E320 = paramMap.get("RE320");
        switch (E320.intValue()) {
            case 0:
                return calculate(new Param("RE325"));
            case 1:
                return calculate(new Param("RE324_3"));
            case 2:
                return calculate(new Param("RE324_2"));
            case 3:
                return calculate(new Param("RE324_1"));
            default:
                return -1.0;
        }
    }

    /**
     * 处理特殊公式272  =  	IF(AND(E326>MAX(E323,E324),E325<E326),1,0)
     * 计算 RE329
     *
     * @return 结算结果
     */
    private Double calculateRE329() {
        Double E323 = paramMap.get("RE323");
        Double E324 = paramMap.get("RE324");
        Double E325 = paramMap.get("RE325");
        Double E326 = paramMap.get("RE326");
        if (null == E323 || null == E324 || null == E325 || null == E326)
            return null;
        return (E326 > Math.max(E323, E324) && E326 < E325) ? 1.0 : 0.0;
    }

    /**
     * 处理特殊公式276  =  IF(GE129<45,1,2)
     * 计算 RE331
     *
     * @return 结算结果
     */
    private Double calculateRE331() {
        Double GE129 = calculate(new Param("GE129"));
        if (null == GE129)
            return null;
        return GE129 < 45 ? 1.0 : 2.0;
    }

    public Double calculateMill(Param param) {
        Double value = dealMillSpecial(param.getParamName());
        return null;
    }

    private Double dealMillSpecial(String formulaName) {
        return null;
    }

    public Map<String, Formula> getFormulaMapByType(int type) {
        Map<String, Formula> map = new HashMap<>();
        List<Formula> list = expressionDao.getFormulaListByType(type);
        for (Formula formula : list) {
            map.put(formula.getFormulaName(), formula);
        }
        return map;
    }

}
